# -*- coding: utf-8 -*-
'''
  @author zhanghaisheng
  @date 2021/9/2
  @description get python code_coverage result
'''
from __future__ import division
import os
import requests
from xml.dom.minidom import parse, parseString
from ci_conclude.const import CODE
from ci_conclude.base import BaseConclude
from ci_conclude.qingstor import get_qingstor_path

PYTHON_SUFFIX_SET = {'.py'}
python_lines = 0
python_file_nums = 0

class CoveragePyConclude(BaseConclude):

    # 解析coverage统计的python代码覆盖率，python_project_path为python工程根目录，.coverage文件也存在于此目录
    def get_python_coverage(self, coverage_xml_path):
        if coverage_xml_path.startswith("http"):
            res = requests.get(coverage_xml_path)
            if res.status_code == 200 and res.ok:
                domTree = parseString(res.text)
            else:
                return {}
        else:
            if os.path.exists(coverage_xml_path) is False:
                return 'pycov.xml not exist!'
            python_project_path = coverage_xml_path.replace('/pycov.xml', '')
            domTree = parse(coverage_xml_path)
        if domTree is None:
            return 'no data!'
        else:
            global python_file_nums
            global python_lines
            rootNode = domTree.documentElement  # 获取coverage.xml文档根元素
            line_rate = lines_covered = ''
            class_num = 0
            packages_covered = 0
            line_rate = rootNode.getAttribute("line-rate")
            lines_covered = rootNode.getAttribute("lines-covered")
            python_lines = int(rootNode.getAttribute("python_lines"))
            python_file_nums = int(rootNode.getAttribute("python_file_nums"))
            packages = rootNode.getElementsByTagName("packages")[0].getElementsByTagName("package")  # 获取元素内特定标签元素
            packages_covered = len(packages)
            if packages is not None:
                for package in packages:
                    classeses = package.getElementsByTagName("classes")
                    for classes in classeses:
                        class_num += len(classes.getElementsByTagName("class"))
            # self.list_python_files(python_project_path)
            covered = int(lines_covered)
            if python_lines == 0:
                coverage = "0%"
            else:
                coverage = round(covered / python_lines, 2)
            print('file_nums: ' + str(python_file_nums))
            print('covered_file_num: ' + str(class_num))
            print('total_lines: ' + str(python_lines))
            print('covered_lines: ' + str(covered))
            print('coveraged: ' + str(int(round(float(line_rate), 2) * 100)) + '%')
            print(f'total_coverage:  {coverage}')
            print('packages_covered: ' + str(packages_covered))
            data = {
                    "packages_covered": packages_covered, # 总覆盖包数
                    "file_nums": python_file_nums,  # 总python文件数
                    "covered_file_num": class_num,  # 覆盖的python文件数
                    "total_lines": python_lines,  # 总行数
                    "covered_lines": covered,  # 已覆盖行数
                    "coveraged": round(float(line_rate), 2),  # 已覆盖文件的覆盖率
                    "total_coverage": coverage  # 总覆盖率
                   }
            result = dict(code=CODE.PASS.ID, message=CODE.PASS.NAME, data=data, prefix="cov_py")
            return result

    # 统计工程目录下所有python文件总有效行数，如果测试代码也在底下的话会一起统计，所以最好传开发源码根目录
    def list_python_files(self, python_project_path):
        '''
        遍历工程路径path，如果遇到文件则统计其行数，如果遇到目录则进行递归
        '''
        files = os.listdir(python_project_path)
        for f in files:
            file = os.path.join(python_project_path, f)
            if (os.path.isfile(file)):
                suffix = os.path.splitext(file)[-1]
                if suffix in PYTHON_SUFFIX_SET:
                    self.count_pycode_nums(file)
            if (os.path.isdir(file)):
                self.list_python_files(file)

    # 统计单一python文件总有效行数
    def count_pycode_nums(self, file):
        """
        :param file: 文件路径，.py文件
        :rtype :int
        """
        global python_lines
        global python_file_nums
        with open(file, encoding='utf-8') as data:
            count, flag = 0, 0
            begin = ('"""', "'''")
            for line in data:
                line2 = line.strip()
                if line2.startswith('#'):
                    continue
                elif line2.startswith(begin):
                    if line2.endswith(begin) and len(line2) > 3:
                        flag = 0
                        continue
                    elif flag == 0:
                        flag = 1
                    else:
                        flag = 0
                        continue
                elif flag == 1 and line2.endswith(begin):
                    flag = 0
                    continue
                if flag == 0 and line2:
                    count += 1
        # print(str(file).replace(project_path + '\\', '') + "," + str(count) + "," + str(count) + ",0%")
        python_lines += count
        python_file_nums += 1
        return count

    def get_url(self, coverage_xml_path):
        pycov_root_path = "opt/Report/pycov-ut"
        qingstor_path = get_qingstor_path(pycov_root_path, job_name=self.project_name, build_id=self.buildid, namespace='coverage', product=self.product)
        coverage_url = f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/{qingstor_path}/index.html"
        return coverage_url

    def get_result(self, coverage_xml_path):
        return self.get_python_coverage(coverage_xml_path)

    def format_to_weixin(self, result_kwargs, url):
        """
            result_kwargs: {'code': -1, 'message': 'FAIL',
                    'data': {
                            "line_nums": str(int(covered_lines) + int(missed_lines)),  # 总行数
                            "line_coverage": coverage_line,  # 行覆盖率
                            "method_nums": str(int(covered_methods) + int(missed_methods)),  # 总方法数
                            "method_coverage": coverage_method,  # 方法覆盖率
                            "class_nums": str(int(covered_classes) + int(missed_classes)),  # 总类数
                            "class_coverage": coverage_class,  # 类覆盖率
                            "package_nums": len(packages)  # package数量
                        }}
            url: http://ecarx.stor.ecarx.com.cn/autobuildtestline/{qingstor_path}/index.html
        """
        # title = f"#【{self.project_name}】pipeline #{self.buildid} [stage: {self.stage_name}] 统计结果"
        if result_kwargs:
            content = (f"""\n ## [{self.stage_name} Report] [{result_kwargs["message"]}] [报告地址]({url}) """
                    f"""\n > [总行数]: <font color="common">{result_kwargs["data"]["total_lines"]}</font> """
                    f"""\n > [覆盖行数]: <font color="common">{result_kwargs["data"]["covered_lines"]}</font> """
                    f"""\n > [总文件数]: <font color="common">{result_kwargs["data"]["file_nums"]}</font> """
                    f"""\n > [覆盖文件数]: <font color="common">{result_kwargs["data"]["covered_file_num"]}</font> """
                    f"""\n > [已覆盖文件的覆盖率]: <font color="common">{result_kwargs["data"]["coveraged"] * 100}%</font> """
                    f"""\n > [总覆盖率]: <font color="common">{result_kwargs["data"]["total_coverage"] * 100}%</font> """
                    f"""\n > [包覆盖数]: <font color="common">{result_kwargs["data"]["packages_covered"]}</font> """)
        else:
            content = f"""\n ## [{self.stage_name} Report] \n <font color="warning">暂无数据</font>"""
        return content
